Completed
Push — development ( 5236fa...488938 )
by Stephen
20s
created

elk_ViewVersions.determineVersions   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
/*!
2
 * @name      ElkArte Forum
3
 * @copyright ElkArte Forum contributors
4
 * @license   BSD http://opensource.org/licenses/BSD-3-Clause
5
 *
6
 * This file contains code covered by:
7
 * copyright:	2011 Simple Machines (http://www.simplemachines.org)
8
 * license:		BSD, See included LICENSE.TXT for terms and conditions.
9
 *
10
 * @version 1.1
11
 */
12
13
/**
14
 * Handle the JavaScript surrounding the admin and moderation center.
15
 */
16
17
/**
18
 * We like the globals cuz they is good to us
19
 */
20
21
/** global: previewTimeout, origText, valid, warningMessage, previewData, refreshPreviewCache, add_answer_template */
22
/** global: txt_add_another_answer, last_preview, txt_preview, elk_scripturl, txt_news_error_no_news, oThumbnails, elk_smiley_url */
23
/** global: db_vis, database_changes_area, elk_session_var, package_ftp_test, package_ftp_test_connection, package_ftp_test_failed */
24
/** global: onNewFolderReceived, elk_session_id, membersSwap, elk_images_url, maintain_members_choose, maintain_members_all */
25
/** global: reattribute_confirm, reattribute_confirm_email, reattribute_confirm_username, oModeratorSuggest, permission_profiles */
26
/** global: txt_save, txt_permissions_profile_rename, ajax_notification_cancel_text, txt_theme_remove_confirm, XMLHttpRequest */
27
/** global: theme_id, frames, editFilename, txt_ban_name_empty, txt_ban_restriction_empty, ElkInfoBar, txt_invalid_response */
28
/** global: feature_on_text, feature_off_text, core_settings_generic_error, startOptID, add_question_template, question_last_blank */
29
/** global: ourLanguageVersions, ourVersions, txt_add_another_answer, txt_permissions_commit, Image */
30
31
/**
32
 * Admin index class with the following methods
33
 * elk_AdminIndex(oOptions)
34
 * {
35
 *		public init()
36
 *		public loadAdminIndex()
37
 *		public setAnnouncements()
38
 *		public showCurrentVersion()
39
 *		public checkUpdateAvailable()
40
 * }
41
 *
42
 * @param {object} oOptions
43
 */
44
function elk_AdminIndex(oOptions)
45
{
46
	this.opt = oOptions;
47
	this.announcements = [];
48
	this.current = {};
49
	this.init_news = false;
50
	this.init();
51
}
52
53
// Initialize the admin index to handle announcement, current version and updates
54
elk_AdminIndex.prototype.init = function ()
55
{
56
	window.adminIndexInstanceRef = this;
57
58
	window.addEventListener("load", function () {
59
		window.adminIndexInstanceRef.loadAdminIndex();
60
	});
61
};
62
63
elk_AdminIndex.prototype.loadAdminIndex = function ()
64
{
65
	// Load the current master and your version numbers.
66
	if (this.opt.bLoadVersions)
67
		this.showCurrentVersion();
68
69
	// Load the text box that says there's a new version available.
70
	if (this.opt.bLoadUpdateNotification)
71
		this.checkUpdateAvailable();
72
};
73
74
// Update the announcement container with news
75
elk_AdminIndex.prototype.setAnnouncement = function (announcement)
76
{
77
	var oElem = document.getElementById(this.opt.sAnnouncementContainerId),
78
		sMessages = this.init_news ? oElem.innerHTML : '',
79
		sMessage = '';
80
81
	sMessage = this.opt.sAnnouncementMessageTemplate.replace('%href%', announcement.html_url).replace('%subject%', announcement.name).replace('%time%', announcement.published_at.replace(/[TZ]/g, ' ')).replace('%message%', announcement.body).replace(/\n/g, '<br />').replace(/\r/g, '');
82
83
	oElem.innerHTML = sMessages + this.opt.sAnnouncementTemplate.replace('%content%', sMessage);
84
	this.init_news = true;
85
};
86
87
// Updates the current version container with the current version found in the repository
88
elk_AdminIndex.prototype.showCurrentVersion = function ()
89
{
90
	var oElkVersionContainer = document.getElementById(this.opt.slatestVersionContainerId),
91
		oinstalledVersionContainer = document.getElementById(this.opt.sinstalledVersionContainerId),
92
		sCurrentVersion = oinstalledVersionContainer.innerHTML,
93
		adminIndex = this,
94
		elkVersion = '???',
95
		verCompare = new elk_ViewVersions();
96
97
	$.getJSON('https://api.github.com/repos/elkarte/Elkarte/releases', {format: "json"},
98
	function(data, textStatus, jqXHR) {
0 ignored issues
show
Unused Code introduced by
The parameter jqXHR is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
Unused Code introduced by
The parameter textStatus is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
99
		var mostRecent = {},
100
			previous = {};
101
		adminIndex.current = adminIndex.normalizeVersion(sCurrentVersion);
102
103
		$.each(data, function(idx, elem) {
104
			// No drafts, thank you
105
			if (elem.draft)
106
				return;
107
108
			var release = adminIndex.normalizeVersion(elem.tag_name);
109
110
			if (!previous.hasOwnProperty('major') || verCompare.compareVersions(sCurrentVersion, elem.tag_name.replace('-', '').substring(1)))
111
			{
112
				// Using a preprelease? Then you may need to know a new one is out!
113
				if ((elem.prerelease && adminIndex.current.prerelease) || (!elem.prerelease))
114
				{
115
					previous = release;
116
					mostRecent = elem;
117
				}
118
			}
119
120
			// Load the text box containing the latest news items.
121
			if (adminIndex.opt.bLoadAnnouncements)
122
				adminIndex.setAnnouncement(elem);
123
		});
124
		elkVersion = mostRecent.name.replace(/elkarte/i, '').trim();
125
126
		oElkVersionContainer.innerHTML = elkVersion;
127
		if (verCompare.compareVersions(sCurrentVersion, elkVersion))
128
			oinstalledVersionContainer.innerHTML = adminIndex.opt.sVersionOutdatedTemplate.replace('%currentVersion%', sCurrentVersion);
129
	});
130
};
131
132
// Compare two different versions and return true if the firs is higher than the second
133
elk_AdminIndex.prototype.compareVersion = function (curVer, refVer)
134
{
135
	if (curVer.major > refVer.major)
136
		return true;
137
	else if (curVer.major < refVer.major)
138
		return false;
139
140
	if (curVer.minor > refVer.minor)
141
		return true;
142
	else if (curVer.minor < refVer.minor)
143
		return false;
144
145
	if (curVer.micro > refVer.micro)
146
		return true;
147
	else if (curVer.micro < refVer.micro)
148
		return false;
149
150
	if (curVer.prerelease)
151
	{
152
		if (curVer.nano > refVer.nano)
153
			return true;
154
		else if (curVer.nano < refVer.nano)
155
			return false;
156
	}
157
158
	return false;
159
};
160
161
// Split a string representing a version number into an object
162
elk_AdminIndex.prototype.normalizeVersion = function (sVersion)
163
{
164
	var splitVersion = sVersion.split(/[\s-]/),
165
	normalVersion = {
166
		major: 0,
167
		minor: 0,
168
		micro: 0,
169
		prerelease: false,
170
		status: 0,
171
		nano: 0
172
	},
173
	prerelease = false,
174
	aDevConvert = {'dev': 0, 'alpha': 1, 'beta': 2, 'rc': 3, 'stable': 4};
175
176
	for (var i = 0; i < splitVersion.length; i++)
177
	{
178
		if (splitVersion[i].toLowerCase() === 'elkarte')
179
			continue;
180
181
		if (splitVersion[i].substring(0, 3).toLowerCase() === 'dev' || splitVersion[i].substring(0, 5).toLowerCase() === 'alpha' || splitVersion[i].substring(0, 4).toLowerCase() === 'beta' || splitVersion[i].substring(0, 2).toLowerCase() === 'rc')
182
		{
183
			normalVersion.prerelease = true;
184
			prerelease = true;
185
186
			// the tag name comes with the number attached to the beta/rc
187
			if (splitVersion[i].indexOf('.') > 0)
188
			{
189
				var splitPre = splitVersion[i].split('.');
190
				normalVersion.nano = parseFloat(splitPre[1]);
191
				normalVersion.nano = parseFloat(splitVersion[i].substr(splitVersion[i].indexOf('.') + 1));
192
				normalVersion.status = aDevConvert[splitVersion[i].substr(0, splitVersion[i].indexOf('.')).toLowerCase()];
193
			}
194
		}
195
196
		// If we have passed a "beta" or an "RC" string, no need to go further
197
		if (prerelease)
198
		{
199
			// Only numbers and dots means a number
200
			if (splitVersion[i].replace(/[\d\.]/g, '') === '')
201
				normalVersion.nano = parseFloat(splitVersion[i]);
202
203
			continue;
204
		}
205
206
		// Likely from the tag
207
		if (splitVersion[i].substring(0, 1) === 'v')
208
			splitVersion[i] = splitVersion[i].substring(1);
209
210
		// Only numbers and dots means a number
211
		if (splitVersion[i].replace(/[\d\.]/g, '') === '')
212
		{
213
			var ver = splitVersion[i].split('.');
214
			normalVersion.major = parseInt(ver[0]);
215
			normalVersion.minor = parseInt(ver[1]);
216
			normalVersion.micro = ver.length > 2 ? parseInt(ver[2]) : 0;
217
		}
218
	}
219
	return normalVersion;
220
};
221
222
// Checks if a new version of ElkArte is available and if so updates the admin info box
223
elk_AdminIndex.prototype.checkUpdateAvailable = function ()
224
{
225
	if (!('ourUpdatePackage' in window))
226
		return;
227
228
	var oContainer = document.getElementById(this.opt.sUpdateNotificationContainerId);
229
230
	// Are we setting a custom title and message?
231
	var sTitle = 'ourUpdateTitle' in window ? window.ourUpdateTitle : this.opt.sUpdateNotificationDefaultTitle,
232
		sMessage = 'ourUpdateNotice' in window ? window.ourUpdateNotice : this.opt.sUpdateNotificationDefaultMessage;
233
234
	oContainer.innerHTML = this.opt.sUpdateNotificationTemplate.replace('%title%', sTitle).replace('%message%', sMessage);
235
236
	// Parse in the package download URL if it exists in the string.
237
	document.getElementById('update-link').href = this.opt.sUpdateNotificationLink.replace('%package%', window.ourUpdatePackage);
238
239
	// If we decide to override life into "red" mode, do it.
240
	if ('elkUpdateCritical' in window)
241
	{
242
		document.getElementById('update_title').style.backgroundColor = '#dd2222';
243
		document.getElementById('update_title').style.color = 'white';
244
		document.getElementById('update_message').style.backgroundColor = '#eebbbb';
245
		document.getElementById('update_message').style.color = 'black';
246
	}
247
};
248
249
/*
250
	elk_ViewVersions(oOptions)
251
	{
252
		public init()
253
		public loadViewVersions
254
		public swapOption(oSendingElement, sName)
255
		public compareVersions(sCurrent, sTarget)
256
		public determineVersions()
257
	}
258
*/
259
function elk_ViewVersions (oOptions)
260
{
261
	this.opt = oOptions;
262
	this.oSwaps = {};
263
	this.init();
264
}
265
266
// initialize the version checker
267
elk_ViewVersions.prototype.init = function ()
268
{
269
	// Load this on loading of the page.
270
	window.viewVersionsInstanceRef = this;
271
	window.addEventListener("load", function () {
272
		window.viewVersionsInstanceRef.loadViewVersions();
273
	});
274
};
275
276
// Load all the file versions
277
elk_ViewVersions.prototype.loadViewVersions = function ()
278
{
279
	this.determineVersions();
280
};
281
282
elk_ViewVersions.prototype.swapOption = function (oSendingElement, sName)
283
{
284
	// If it is undefined, or currently off, turn it on - otherwise off.
285
	this.oSwaps[sName] = !(sName in this.oSwaps) || !this.oSwaps[sName];
286
	if (this.oSwaps[sName])
287
		$("#" + sName).show(300);
288
	else
289
		$("#" + sName).hide(300);
290
291
	// Unselect the link and return false.
292
	oSendingElement.blur();
293
294
	return false;
295
};
296
297
// compare a current and target version to determine if one is newer/older
298
elk_ViewVersions.prototype.compareVersions = function (sCurrent, sTarget)
299
{
300
	var aVersions = [],
301
		aParts = [],
0 ignored issues
show
Unused Code introduced by
The assignment to variable aParts seems to be never used. Consider removing it.
Loading history...
302
		aCompare = [sCurrent, sTarget],
303
		aDevConvert = {'dev': 0, 'alpha': 1, 'beta': 2, 'rc': 3};
304
305
	for (var i = 0; i < 2; i++)
306
	{
307
		// Clean the version and extract the version parts.
308
		var sClean = aCompare[i].toLowerCase().replace(/ /g, '').replace(/release candidate/g, 'rc');
309
		aParts = sClean.match(/(\d+)(?:\.(\d+|))?(?:\.)?(\d+|)(?:(alpha|beta|rc)\.*(\d+|)(?:\.)?(\d+|))?(?:(dev))?(\d+|)/);
310
311
		// No matches?
312
		if (aParts === null)
313
			return false;
314
315
		// Build an array of parts.
316
		aVersions[i] = [
317
			aParts[1] > 0 ? parseInt(aParts[1]) : 0,
318
			aParts[2] > 0 ? parseInt(aParts[2]) : 0,
319
			aParts[3] > 0 ? parseInt(aParts[3]) : 0,
320
			typeof(aParts[4]) === 'undefined' ? 'stable' : aDevConvert[aParts[4]],
321
			aParts[5] > 0 ? parseInt(aParts[5]) : 0,
322
			aParts[6] > 0 ? parseInt(aParts[6]) : 0,
323
			typeof(aParts[7]) !== 'undefined' ? 'dev' : ''
324
		];
325
	}
326
327
	// Loop through each category.
328
	for (i = 0; i < 7; i++)
329
	{
330
		// Is there something for us to calculate?
331
		if (aVersions[0][i] !== aVersions[1][i])
332
		{
333
			// Dev builds are a problematic exception.
334
			// (stable) dev < (stable) but (unstable) dev = (unstable)
335
			if (i === 3)
336
				return aVersions[0][i] < aVersions[1][i] ? !aVersions[1][6] : aVersions[0][6];
337
			else if (i === 6)
338
				return aVersions[0][6] ? aVersions[1][3] === 'stable' : false;
339
			// Otherwise a simple comparison.
340
			else
341
				return aVersions[0][i] < aVersions[1][i];
342
		}
343
	}
344
345
	// They are the same!
346
	return false;
347
};
348
349
// For each area of ElkArte, determine the current and installed versions
350
elk_ViewVersions.prototype.determineVersions = function ()
351
{
352
	var oHighYour = {
353
		sources: '??',
354
		admin: '??',
355
		controllers: '??',
356
		database: '??',
357
		subs: '??',
358
		'default': '??',
359
		Languages: '??',
360
		Templates: '??'
361
	};
362
	var oHighCurrent = {
363
		sources: '??',
364
		admin: '??',
365
		controllers: '??',
366
		database: '??',
367
		subs: '??',
368
		'default': '??',
369
		Languages: '??',
370
		Templates: '??'
371
	};
372
	var oLowVersion = {
373
		sources: false,
374
		admin: false,
375
		controllers: false,
376
		database: false,
377
		subs: false,
378
		'default': false,
379
		Languages: false,
380
		Templates: false
381
	};
382
383
	var sSections = [
384
		'sources',
385
		'admin',
386
		'controllers',
387
		'database',
388
		'subs',
389
		'default',
390
		'Languages',
391
		'Templates'
392
	];
393
394
	var sCurVersionType = '',
395
		sinstalledVersion,
396
		oSection,
397
		oSectionLink;
398
399
	for (var i = 0, n = sSections.length; i < n; i++)
400
	{
401
		// Collapse all sections.
402
		oSection = document.getElementById(sSections[i]);
403
404
		if (typeof(oSection) === 'object' && oSection !== null)
405
			oSection.style.display = 'none';
406
407
		// Make all section links clickable.
408
		oSectionLink = document.getElementById(sSections[i] + '-link');
409
		if (typeof(oSectionLink) === 'object' && oSectionLink !== null)
410
		{
411
			oSectionLink.onclick = function (oEvent) {
412
				this.swapOption(oEvent.target, oEvent.target.id.split('-')[0]);
413
				return false;
414
			}.bind(this);
415
		}
416
	}
417
418
	if (!('ourVersions' in window))
419
		window.ourVersions = {};
420
421
	// for each file in the detailed-version.js
422
	for (var sFilename in window.ourVersions)
423
	{
424
		if (!window.ourVersions.hasOwnProperty(sFilename))
425
			continue;
426
427
		if (!document.getElementById('our' + sFilename))
428
			continue;
429
430
		sCurVersionType = '';
431
432
		sinstalledVersion = document.getElementById('your' + sFilename).innerHTML;
433
434
		for (var sVersionType in oLowVersion)
435
		{
436
			if (!oLowVersion.hasOwnProperty(sVersionType))
437
			{
438
				continue;
439
			}
440
441
			if (sFilename.substr(0, sVersionType.length) === sVersionType)
442
			{
443
				sCurVersionType = sVersionType;
444
				break;
445
			}
446
		}
447
448
		if (sCurVersionType === '')
449
			continue;
450
451
		// use compareVersion to determine which version is >< the other
452
		if (typeof(sCurVersionType) !== 'undefined')
453
		{
454
			if ((this.compareVersions(oHighYour[sCurVersionType], sinstalledVersion) || oHighYour[sCurVersionType] === '??') && !oLowVersion[sCurVersionType])
455
				oHighYour[sCurVersionType] = sinstalledVersion;
456
457
			if (this.compareVersions(oHighCurrent[sCurVersionType], ourVersions[sFilename]) || oHighCurrent[sCurVersionType] === '??')
458
				oHighCurrent[sCurVersionType] = ourVersions[sFilename];
459
460
			if (this.compareVersions(sinstalledVersion, ourVersions[sFilename]))
461
			{
462
				oLowVersion[sCurVersionType] = sinstalledVersion;
463
				document.getElementById('your' + sFilename).style.color = 'red';
464
			}
465
		}
466
		else if (this.compareVersions(sinstalledVersion, ourVersions[sFilename]))
467
			oLowVersion[sCurVersionType] = sinstalledVersion;
468
469
		document.getElementById('our' + sFilename).innerHTML = ourVersions[sFilename];
470
		document.getElementById('your' + sFilename).innerHTML = sinstalledVersion;
471
	}
472
473
	if (!('ourLanguageVersions' in window))
474
		window.ourLanguageVersions = {};
475
476
	for (sFilename in window.ourLanguageVersions)
477
	{
478
		for (i = 0; i < this.opt.aKnownLanguages.length; i++)
479
		{
480
			if (!document.getElementById('our' + sFilename + this.opt.aKnownLanguages[i]))
481
				continue;
482
483
			document.getElementById('our' + sFilename + this.opt.aKnownLanguages[i]).innerHTML = ourLanguageVersions[sFilename];
484
485
			sinstalledVersion = document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).innerHTML;
486
			document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).innerHTML = sinstalledVersion;
487
488
			if ((this.compareVersions(oHighYour.Languages, sinstalledVersion) || oHighYour.Languages === '??') && !oLowVersion.Languages)
489
				oHighYour.Languages = sinstalledVersion;
490
491
			if (this.compareVersions(oHighCurrent.Languages, ourLanguageVersions[sFilename]) || oHighCurrent.Languages === '??')
492
				oHighCurrent.Languages = ourLanguageVersions[sFilename];
493
494
			if (this.compareVersions(sinstalledVersion, ourLanguageVersions[sFilename]))
495
			{
496
				oLowVersion.Languages = sinstalledVersion;
497
				document.getElementById('your' + sFilename + this.opt.aKnownLanguages[i]).style.color = 'red';
498
			}
499
		}
500
	}
501
502
	// Set the column titles based on the files each contain
503
	for (i = 0, n = sSections.length; i < n; i++)
504
	{
505
		if (sSections[i] === 'Templates')
506
			continue;
507
508
		document.getElementById('your' + sSections[i]).innerHTML = oLowVersion[sSections[i]] ? oLowVersion[sSections[i]] : oHighYour[sSections[i]];
509
		document.getElementById('our' + sSections[i]).innerHTML = oHighCurrent[sSections[i]];
510
		if (oLowVersion[sSections[i]])
511
			document.getElementById('your' + sSections[i]).style.color = 'red';
512
	}
513
514
	// Custom theme in use?
515
	if (document.getElementById('Templates'))
516
	{
517
		document.getElementById('yourTemplates').innerHTML = oLowVersion.Templates ? oLowVersion.Templates : oHighYour.Templates;
518
		document.getElementById('ourTemplates').innerHTML = oHighCurrent.Templates;
519
520
		if (oLowVersion.Templates)
521
			document.getElementById('yourTemplates').style.color = 'red';
522
	}
523
};
524
525
/**
526
 * Adds a new word container to the censored word list
527
 */
528
function addNewWord()
529
{
530
	setOuterHTML(document.getElementById('moreCensoredWords'), '<div class="censorWords"><input type="text" name="censor_vulgar[]" size="30" class="input_text" /> <i class="icon i-chevron-circle-right"></i> <input type="text" name="censor_proper[]" size="30" class="input_text" /><' + '/div><div id="moreCensoredWords"><' + '/div>');
531
}
532
533
/**
534
 * Will enable/disable checkboxes, according to if the BBC globally set or not.
535
 *
536
 * @param {string} section id of the container
537
 * @param {string} disable true or false
538
 */
539
function toggleBBCDisabled(section, disable)
540
{
541
	var elems = document.getElementById(section).getElementsByTagName('*');
542
543
	for (var i = 0; i < elems.length; i++)
544
	{
545
		if (typeof(elems[i].name) === "undefined" || (elems[i].name.substr((section.length + 1), (elems[i].name.length - 2 - (section.length + 1))) !== "enabledTags") || (elems[i].name.indexOf(section) !== 0))
546
			continue;
547
548
		elems[i].disabled = disable;
549
	}
550
	document.getElementById("bbc_" + section + "_select_all").disabled = disable;
551
}
552
553
/**
554
 * Keeps the input boxes display options appropriate for the options selected
555
 * when adding custom profile fields
556
 */
557
function updateInputBoxes()
558
{
559
	var curType = document.getElementById("field_type").value,
560
		privStatus = document.getElementById("private").value,
561
		stdText = ['text', 'textarea', 'email', 'url', 'color', 'date'],
562
		stdInput = ['text', 'email', 'url', 'color', 'date'],
563
		stdSelect = ['select'];
564
565
	var bIsStd = (stdInput.indexOf(curType) !== -1),
566
		bIsText = (stdText.indexOf(curType) !== -1),
567
		bIsSelect = (stdSelect.indexOf(curType) !== -1);
568
569
	// Only Text like fields can see a max length input
570
	document.getElementById("max_length_dt").style.display = bIsText ? "" : "none";
571
	document.getElementById("max_length_dd").style.display = bIsText ? "" : "none";
572
573
	// Textareas can get a row/col definition
574
	document.getElementById("dimension_dt").style.display = curType === "textarea" ? "" : "none";
575
	document.getElementById("dimension_dd").style.display = curType === "textarea" ? "" : "none";
576
577
	// Text like fields can be styled with bbc
578
	document.getElementById("bbc_dt").style.display = bIsText ? "" : "none";
579
	document.getElementById("bbc_dd").style.display = bIsText ? "" : "none";
580
581
	// And given defaults
582
	document.getElementById("defaultval_dt").style.display = bIsText ? "" : "none";
583
	document.getElementById("defaultval_dd").style.display = bIsText ? "" : "none";
584
585
	// Selects and radio can support a list of options
586
	document.getElementById("options_dt").style.display = curType === "select" || curType === "radio" ? "" : "none";
587
	document.getElementById("options_dd").style.display = curType === "select" || curType === "radio" ? "" : "none";
588
589
	// Checkboxes can have a default
590
	document.getElementById("default_dt").style.display = curType === "check" ? "" : "none";
591
	document.getElementById("default_dd").style.display = curType === "check" ? "" : "none";
592
593
	// Normal input boxes can use a validation mask as well
594
	document.getElementById("mask_dt").style.display = bIsStd ? "" : "none";
595
	document.getElementById("mask").style.display = bIsStd ? "" : "none";
596
597
	// And text and select fields are searchable
598
	document.getElementById("can_search_dt").style.display = bIsText || bIsSelect ? "" : "none";
599
	document.getElementById("can_search_dd").style.display = bIsText || bIsSelect ? "" : "none";
600
601
	// Moving to a non searchable field, be sure searchable is unselected.
602
	if (!bIsText && !bIsSelect)
603
		document.getElementById("can_search_dd").checked = false;
604
605
	// Using regex in the mask, give them a place to supply the regex
606
	document.getElementById("regex_div").style.display = bIsStd && document.getElementById("mask").value === "regex" ? "" : "none";
607
	document.getElementById("display").disabled = false;
608
609
	// Cannot show this on the topic
610
	if (curType === "textarea" || privStatus >= 2)
611
	{
612
		document.getElementById("display").checked = false;
613
		document.getElementById("display").disabled = true;
614
	}
615
}
616
617
/**
618
 * Used to add additional radio button options when editing a custom profile field
619
 */
620
function addOption()
621
{
622
	setOuterHTML(document.getElementById("addopt"), '<br /><input type="radio" name="default_select" value="' + startOptID + '" id="' + startOptID + '" /><input type="text" name="select_option[' + startOptID + ']" value="" class="input_text" /><span id="addopt"></span>');
623
	startOptID++;
624
}
625
626
/**
627
 * Adds another question to the registration page
628
 */
629
function addAnotherQuestion()
630
{
631
	var placeHolder = document.getElementById('add_more_question_placeholder');
632
633
	setOuterHTML(placeHolder, add_question_template.easyReplace({
634
		question_last_blank: question_last_blank,
635
		setup_verification_add_more_answers: txt_add_another_answer
636
	}));
637
638
	question_last_blank++;
639
}
640
641
/**
642
 * Every question should have an answer, even if its a lie
643
 *
644
 * @param {HTMLElement} elem
645
 * @param {string} question_name
646
 */
647
function addAnotherAnswer(elem, question_name)
648
{
649
	setOuterHTML(elem, add_answer_template.easyReplace({
650
		question_last_blank: question_name,
651
		setup_verification_add_more_answers: txt_add_another_answer
652
	}));
653
}
654
655
/**
656
 * Used to add new search engines to the known list
657
 *
658
 * @param {string} txt_name
659
 * @param {string} txt_url
660
 * @param {string} txt_word_sep
661
 */
662
function addAnotherSearch(txt_name, txt_url, txt_word_sep)
663
{
664
	var placeHolder = document.getElementById('add_more_searches'),
665
		newDT = document.createElement("dt"),
666
		newInput = document.createElement("input"),
667
		newLabel = document.createElement("label"),
668
		newDD = document.createElement("dd");
669
670
	newInput.name = "engine_name[]";
671
	newInput.type = "text";
672
	newInput.className = "input_text";
673
	newInput.size = "50";
674
	newInput.setAttribute("class", "verification_question");
675
676
	// Add the label and input box to the DOM
677
	newLabel.textContent = txt_name + ': ';
678
	newLabel.appendChild(newInput);
679
	newDT.appendChild(newLabel);
680
681
	// Next input box
682
	newInput = document.createElement("input");
683
	newInput.name = "engine_url[]";
684
	newInput.type = "text";
685
	newInput.className = "input_text";
686
	newInput.size = "35";
687
	newInput.setAttribute("class", "input_text verification_answer");
688
689
	// Add the new label and input box
690
	newLabel = document.createElement("label");
691
	newLabel.textContent = txt_url + ': ';
692
	newLabel.appendChild(newInput);
693
	newDD.appendChild(newLabel);
694
	newDD.appendChild(document.createElement("br"));
695
696
	// Rinse and repeat
697
	newInput = document.createElement("input");
698
	newInput.name = "engine_separator[]";
699
	newInput.type = "text";
700
	newInput.className = "input_text";
701
	newInput.size = "5";
702
	newInput.setAttribute("class", "input_text verification_answer");
703
704
	newLabel = document.createElement("label");
705
	newLabel.textContent = txt_word_sep + ': ';
706
	newLabel.appendChild(newInput);
707
	newDD.appendChild(newLabel);
708
709
	placeHolder.parentNode.insertBefore(newDT, placeHolder);
710
	placeHolder.parentNode.insertBefore(newDD, placeHolder);
711
}
712
713
/**
714
 * News admin page
715
 */
716
function addAnotherNews()
717
{
718
	var last = $("#list_news_lists_last"),
719
		$new_item = last.clone();
720
721
	last_preview++;
722
	$new_item.attr('id', 'list_news_lists_' + last_preview);
723
	$new_item.find('textarea').attr('id', 'data_' + last_preview);
724
	$new_item.find('#preview_last').attr('id', 'preview_' + last_preview);
725
	$new_item.find('#box_preview_last').attr('id', 'box_preview_' + last_preview);
726
727
	last.before($new_item);
728
	$new_item.toggle();
729
	make_preview_btn(last_preview);
730
}
731
732
/**
733
 * Makes the preview button when in manage news
734
 *
735
 * @param {string} preview_id
736
 */
737
function make_preview_btn (preview_id)
738
{
739
	var $id = $("#preview_" + preview_id);
740
741
	$id.text(txt_preview).on('click', function () {
742
		$.ajax({
743
			type: "POST",
744
			url: elk_scripturl + "?action=xmlpreview;xml",
745
			data: {item: "newspreview", news: $("#data_" + preview_id).val()},
746
			context: document.body
747
		})
748
		.done(function(request) {
749
			if ($(request).find("error").text() === '')
750
				$(document).find("#box_preview_" + preview_id).html($(request).text());
751
			else
752
				$(document).find("#box_preview_" + preview_id).text(txt_news_error_no_news);
753
		});
754
	});
755
756
	if (!$id.parent().hasClass('linkbutton_right'))
757
		$id.wrap('<a class="linkbutton_right" href="javascript:void(0);"></a>');
758
}
759
760
/**
761
 * Used by manage themes to show the thumbnail of the theme variant chosen
762
 *
763
 * @param {string} sVariant
764
 */
765
function changeVariant(sVariant)
766
{
767
	document.getElementById('variant_preview').src = oThumbnails[sVariant];
768
}
769
770
/**
771
 * The idea here is simple: don't refresh the preview on every keypress, but do refresh after they type.
772
 *
773
 * @returns {undefined}
774
 */
775
function setPreviewTimeout()
776
{
777
	if (previewTimeout)
778
	{
779
		window.clearTimeout(previewTimeout);
780
		previewTimeout = null;
781
	}
782
783
	previewTimeout = window.setTimeout(function() {refreshPreview(true); previewTimeout = null;}, 500);
784
}
785
786
/**
787
 * Used in manage paid subscriptions to show the fixed duration panel or
788
 * the variable duration panel, based on which radio button is selected
789
 *
790
 * @param {type} toChange
791
 */
792
function toggleDuration(toChange)
0 ignored issues
show
Unused Code introduced by
The parameter toChange is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
793
{
794
	$("#fixed_area").slideToggle(300);
795
	$("#flexible_area").slideToggle(300);
796
}
797
798
/**
799
 * Used when editing the search weights for results, calculates the overall total weight
800
 */
801
function calculateNewValues()
802
{
803
	var total = 0;
804
	for (var i = 1; i <= 7; i++)
805
	{
806
		total += parseInt(document.getElementById('weight' + i + '_val').value);
807
	}
808
809
	document.getElementById('weighttotal').innerHTML = total;
810
	for (i = 1; i <= 7; i++)
811
	{
812
		document.getElementById('weight' + i).innerHTML = (Math.round(1000 * parseInt(document.getElementById('weight' + i + '_val').value) / total) / 10) + '%';
813
	}
814
}
815
816
/**
817
 * Toggle visibility of add smile image source options
818
 */
819
function switchType()
820
{
821
	document.getElementById("ul_settings").style.display = document.getElementById("method-existing").checked ? "none" : "block";
822
	document.getElementById("ex_settings").style.display = document.getElementById("method-upload").checked ? "none" : "block";
823
}
824
825
/**
826
 * Toggle visibility of smiley set should the user want different images in a set (add smiley)
827
 */
828
function swapUploads()
829
{
830
	document.getElementById("uploadMore").style.display = document.getElementById("uploadSmiley").disabled ? "none" : "block";
831
	document.getElementById("uploadSmiley").disabled = !document.getElementById("uploadSmiley").disabled;
832
}
833
834
/**
835
 * Close the options that should not be visible for adding a smiley
836
 *
837
 * @param {string} element
838
 */
839
function selectMethod(element)
840
{
841
	document.getElementById("method-existing").checked = element !== "upload";
842
	document.getElementById("method-upload").checked = element === "upload";
843
}
844
845
/**
846
 * Updates the smiley preview to show the current one chosen
847
 */
848
function updatePreview()
849
{
850
	var currentImage = document.getElementById("preview");
851
	currentImage.src = elk_smiley_url + "/" + document.forms.smileyForm.set.value + "/" + document.forms.smileyForm.smiley_filename.value;
852
}
853
854
/**
855
 * Used in package manager to swap the visibility of database changes
856
 */
857
function swap_database_changes()
858
{
859
	db_vis = !db_vis;
860
	database_changes_area.style.display = db_vis ? "" : "none";
861
862
	return false;
863
}
864
865
/**
866
 * Test the given form credentials to test if an FTP connection can be made
867
 */
868
function testFTP()
869
{
870
	ajax_indicator(true);
871
872
	// What we need to post.
873
	var oPostData = {
874
		0: "ftp_server",
875
		1: "ftp_port",
876
		2: "ftp_username",
877
		3: "ftp_password",
878
		4: "ftp_path"
879
	};
880
881
	var sPostData = "";
882
	for (var i = 0; i < 5; i++)
883
		sPostData = sPostData + (sPostData.length === 0 ? "" : "&") + oPostData[i] + "=" + document.getElementById(oPostData[i]).value.php_urlencode();
884
885
	// Post the data out.
886
	sendXMLDocument(elk_prepareScriptUrl(elk_scripturl) + 'action=admin;area=packages;sa=ftptest;xml;' + elk_session_var + '=' + elk_session_id, sPostData, testFTPResults);
887
}
888
889
/**
890
 * Generate a "test ftp" button.
891
 */
892
function generateFTPTest()
893
{
894
	// Don't ever call this twice!
895
	if (generatedButton)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable generatedButton is declared in the current environment, consider using typeof generatedButton === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
896
		return false;
897
898
	generatedButton = true;
0 ignored issues
show
Bug introduced by
The variable generatedButton seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.generatedButton.
Loading history...
899
900
	// No XML?
901
	if (!document.getElementById("test_ftp_placeholder") && !document.getElementById("test_ftp_placeholder_full"))
902
		return false;
903
904
	// create our test button to call testFTP on click
905
	var ftpTest = document.createElement("input");
906
	ftpTest.type = "button";
907
	ftpTest.className = "submit";
908
	ftpTest.onclick = testFTP;
909
910
	// Set the button value based on which form we are on
911
	if (document.getElementById("test_ftp_placeholder"))
912
	{
913
		ftpTest.value = package_ftp_test;
914
		document.getElementById("test_ftp_placeholder").appendChild(ftpTest);
915
	}
916
	else
917
	{
918
		ftpTest.value = package_ftp_test_connection;
919
		document.getElementById("test_ftp_placeholder_full").appendChild(ftpTest);
920
	}
921
922
	return true;
923
}
924
925
/**
926
 * Callback function of the testFTP function
927
 *
928
 * @param {type} oXMLDoc
929
 */
930
function testFTPResults(oXMLDoc)
931
{
932
	ajax_indicator(false);
933
934
	// This assumes it went wrong!
935
	var wasSuccess = false,
936
		message = package_ftp_test_failed,
937
		results = oXMLDoc.getElementsByTagName('results')[0].getElementsByTagName('result');
938
939
	// Results show we were a success
940
	if (results.length > 0)
941
	{
942
		if (parseInt(results[0].getAttribute('success')) === 1)
943
			wasSuccess = true;
944
		message = results[0].firstChild.nodeValue;
945
	}
946
947
	// place the informative box on screen so the user knows if things went well or poorly
948
	document.getElementById("ftp_error_div").style.display = "";
949
	document.getElementById("ftp_error_div").className = wasSuccess ? "successbox" : "errorbox";
950
	document.getElementById("ftp_error_message").innerHTML = message;
951
}
952
953
/**
954
 * Part of package manager, expands a folders contents to show
955
 * permission levels of files it contains.
956
 * Will use an ajax call to get any permissions it has not loaded
957
 *
958
 * @param {type} folderIdent
959
 * @param {type} folderReal
960
 */
961
function expandFolder(folderIdent, folderReal)
962
{
963
	// See if it already exists.
964
	var possibleTags = document.getElementsByTagName("tr");
965
	var foundOne = false;
966
967
	for (var i = 0; i < possibleTags.length; i++)
968
	{
969
		if (possibleTags[i].id.indexOf("content_" + folderIdent + ":-:") === 0)
970
		{
971
			possibleTags[i].style.display = possibleTags[i].style.display === "none" ? "" : "none";
972
			foundOne = true;
973
		}
974
	}
975
976
	// Got something then we're done.
977
	if (foundOne)
978
	{
979
		return false;
980
	}
981
982
	// Otherwise we need to get the wicked thing.
983
	ajax_indicator(true);
984
	getXMLDocument(elk_prepareScriptUrl(elk_scripturl) + 'action=admin;area=packages;onlyfind=' + folderReal.php_urlencode() + ';sa=perms;xml;' + elk_session_var + '=' + elk_session_id, onNewFolderReceived);
985
986
	return false;
987
}
988
989
/**
990
 * Wrapper function to call expandFolder
991
 */
992
function dynamicExpandFolder()
993
{
994
	expandFolder(this.ident, this.path);
995
996
	return false;
997
}
998
999
/**
1000
 * Used when edit the boards and groups access to them
1001
 *
1002
 * @param {type} operation
1003
 * @param {type} brd_list
1004
 */
1005
function select_in_category(operation, brd_list)
1006
{
1007
	for (var brd in brd_list) {
1008
		if (!brd_list.hasOwnProperty(brd))
1009
			continue;
1010
1011
		document.getElementById(operation + '_brd' + brd_list[brd]).checked = true;
1012
	}
1013
}
1014
1015
/**
1016
 * Server Settings > Caching, toggles input fields on/off as appropriate for
1017
 * a given cache engine selection
1018
 */
1019
$(function() {
1020
	$('#cache_accelerator').change(function() {
1021
		// Hide all the settings
1022
		$('#cache_accelerator').find('option').each(function() {
1023
			$('[id^=' + $(this).val() + '_]').hide();
1024
		});
1025
1026
		// Show the settings of the selected engine
1027
		$('[id^=' + $(this).val() + '_]').show();
1028
	})
1029
	// Trigger a change action so that the form is properly initialized
1030
	.change();
1031
});
1032
1033
/**
1034
 * Server Settings > Caching, toggles input fields on/off as appropriate for
1035
 * a given cache engine selection
1036
 */
1037
function toggleCache ()
1038
{
1039
	var memcache = $('#cache_memcached').parent(),
1040
		cachedir = $('#cachedir').parent();
1041
1042
	// Show the memcache server box only if memcache has been selected
1043
	if (cache_type.value.substr(0, 8) !== "memcache")
0 ignored issues
show
Bug introduced by
The variable cache_type seems to be never declared. If this is a global, consider adding a /** global: cache_type */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1044
	{
1045
		memcache.slideUp();
1046
		memcache.prev().slideUp(100);
1047
	}
1048
	else
1049
	{
1050
		memcache.slideDown();
1051
		memcache.prev().slideDown(100);
1052
	}
1053
1054
	// don't show the directory if its not filebased
1055
	if (cache_type.value === "filebased")
1056
	{
1057
		cachedir.slideDown();
1058
		cachedir.prev().slideDown(100);
1059
	}
1060
	else
1061
	{
1062
		cachedir.slideUp(100);
1063
		cachedir.prev().slideUp(100);
1064
	}
1065
}
1066
1067
/**
1068
 * Hides local / subdomain cookie options in the ACP based on selected choices
1069
 * area=serversettings;sa=cookie
1070
 */
1071
function hideGlobalCookies()
1072
{
1073
	var bUseLocal = document.getElementById("localCookies").checked,
1074
		bUseGlobal = !bUseLocal && document.getElementById("globalCookies").checked;
1075
1076
	// Show/Hide the areas based on what they have chosen
1077
	if (!bUseLocal)
1078
	{
1079
		$("#setting_globalCookies").parent().slideDown();
1080
		$("#globalCookies").parent().slideDown();
1081
	}
1082
	else
1083
	{
1084
		$("#setting_globalCookies").parent().slideUp();
1085
		$("#globalCookies").parent().slideUp();
1086
	}
1087
1088
	// Global selected means we need to reveal the domain input box
1089
	if (bUseGlobal)
1090
	{
1091
		$("#setting_globalCookiesDomain").closest("dt").slideDown();
1092
		$("#globalCookiesDomain").closest("dd").slideDown();
1093
	}
1094
	else
1095
	{
1096
		$("#setting_globalCookiesDomain").closest("dt").slideUp();
1097
		$("#globalCookiesDomain").closest("dd").slideUp();
1098
	}
1099
}
1100
1101
/**
1102
 * Attachments Settings
1103
 */
1104
function toggleSubDir ()
1105
{
1106
	var auto_attach = document.getElementById('automanage_attachments'),
1107
		use_sub_dir = document.getElementById('use_subdirectories_for_attachments'),
1108
		dir_elem = document.getElementById('basedirectory_for_attachments');
1109
1110
	use_sub_dir.disabled = !Boolean(auto_attach.selectedIndex);
1111
	if (use_sub_dir.disabled)
1112
	{
1113
		$(use_sub_dir).slideUp();
1114
		$('#setting_use_subdirectories_for_attachments').parent().slideUp();
1115
1116
		$(dir_elem).slideUp();
1117
		$('#setting_basedirectory_for_attachments').parent().slideUp();
1118
	}
1119
	else
1120
	{
1121
		$(use_sub_dir).slideDown();
1122
		$('#setting_use_subdirectories_for_attachments').parent().slideDown();
1123
1124
		$(dir_elem).slideDown();
1125
		$('#setting_basedirectory_for_attachments').parent().slideDown();
1126
	}
1127
		toggleBaseDir();
1128
}
1129
1130
/**
1131
 * Called by toggleSubDir as part of manage attachments
1132
 */
1133
function toggleBaseDir ()
1134
{
1135
	var auto_attach = document.getElementById('automanage_attachments'),
1136
		sub_dir = document.getElementById('use_subdirectories_for_attachments'),
1137
		dir_elem = document.getElementById('basedirectory_for_attachments');
1138
1139
	if (auto_attach.selectedIndex === 0)
1140
		dir_elem.disabled = 1;
1141
	else
1142
		dir_elem.disabled = !sub_dir.checked;
1143
}
1144
1145
1146
/**
1147
 * Called from purgeinactive users maintenance task, used to show or hide
1148
 * the membergroup list.  If collapsed will select all the member groups if expanded
1149
 * unselect them so the user can choose.
1150
 */
1151
function swapMembers()
1152
{
1153
	var membersForm = document.getElementById('membersForm');
1154
1155
	// Make it close smoothly
1156
	$("#membersPanel").slideToggle(300);
1157
1158
	membersSwap = !membersSwap;
1159
	document.getElementById("membersIcon").src = elk_images_url + (membersSwap ? "/selected_open.png" : "/selected.png");
1160
	document.getElementById("membersText").innerHTML = membersSwap ? maintain_members_choose : maintain_members_all;
1161
1162
	// Check or uncheck them all based on if we are expanding or collasping the area
1163
	for (var i = 0; i < membersForm.length; i++)
1164
	{
1165
		if (membersForm.elements[i].type.toLowerCase() === "checkbox")
1166
			membersForm.elements[i].checked = !membersSwap;
1167
	}
1168
1169
	return false;
1170
}
1171
1172
/**
1173
 * Called from reattribute member posts to build the confirm message for the action
1174
 * Keeps the action button (reattribute) disabled until all necessary fields have been filled
1175
 */
1176
function checkAttributeValidity()
1177
{
1178
	origText = reattribute_confirm;
1179
	valid = true;
1180
1181
	// Do all the fields!
1182
	if (!document.getElementById('to').value)
1183
		valid = false;
1184
1185
	warningMessage = origText.replace(/%member_to%/, document.getElementById('to').value);
1186
1187
	// Using email address to find the member
1188
	if (document.getElementById('type_email').checked)
1189
	{
1190
		if (!document.getElementById('from_email').value)
1191
			valid = false;
1192
1193
		warningMessage = warningMessage.replace(/%type%/, '', reattribute_confirm_email).replace(/%find%/, document.getElementById('from_email').value);
1194
	}
1195
	// Or the user name
1196
	else
1197
	{
1198
		if (!document.getElementById('from_name').value)
1199
			valid = false;
1200
1201
		warningMessage = warningMessage.replace(/%type%/, '', reattribute_confirm_username).replace(/%find%/, document.getElementById('from_name').value);
1202
	}
1203
1204
	document.getElementById('do_attribute').disabled = !valid;
1205
1206
	// Keep checking for a valid form so we can activate the submit button
1207
	setTimeout(function() {checkAttributeValidity();}, 500);
1208
1209
	return valid;
1210
}
1211
1212
/**
1213
 * Enable/disable fields when transferring attachments
1214
 *
1215
 * @returns {undefined}
1216
 */
1217
function transferAttachOptions()
1218
{
1219
	var autoSelect = document.getElementById("auto"),
1220
		autoValue = parseInt(autoSelect.options[autoSelect.selectedIndex].value, 10),
1221
		toSelect = document.getElementById("to"),
1222
		toValue = parseInt(toSelect.options[toSelect.selectedIndex].value, 10);
1223
1224
		toSelect.disabled = autoValue !== 0;
1225
		autoSelect.disabled = toValue !== 0;
1226
}
1227
1228
/**
1229
 * Updates the move confirmation text so its descriptive for the current items
1230
 * being moved.
1231
 *
1232
 * @param {string} confirmText
1233
 */
1234
function confirmMoveTopics(confirmText)
1235
{
1236
	var from = document.getElementById('id_board_from'),
1237
		to = document.getElementById('id_board_to');
1238
1239
	if (from.options[from.selectedIndex].disabled || from.options[to.selectedIndex].disabled)
1240
		return false;
1241
1242
	return confirm(confirmText.replace(/%board_from%/, from.options[from.selectedIndex].text.replace(/^\u2003+\u27A4/, '')).replace(/%board_to%/, to.options[to.selectedIndex].text.replace(/^\u2003+\u27A4/, '')));
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1243
}
1244
1245
/**
1246
 * Hide the search methods area if using sphinx(ql) search
1247
 */
1248
function showhideSearchMethod()
1249
{
1250
	var searchSphinxQl = document.getElementById('search_index_sphinxql').checked,
1251
		searchSphinx = document.getElementById('search_index_sphinx').checked,
1252
		searchhide = searchSphinxQl || searchSphinx,
1253
		searchMethod = $('#search_method');
1254
1255
	if (searchhide)
1256
		searchMethod.slideUp();
1257
	else
1258
		searchMethod.slideDown();
1259
}
1260
1261
/**
1262
 * Used in manageFeatures to show / hide custom level input elements based on the checkbox choices
1263
 * Will show or hide the jquery and jqueryui custom input fields for admins that like to roll the dice
1264
 */
1265
function showhideJqueryOptions()
1266
{
1267
	var jqBase = document.getElementById('jquery_default').checked,
1268
		jqUi = document.getElementById('jqueryui_default').checked,
1269
		jqBase_val = $('#jquery_version'),
1270
		jqUi_val = $('#jqueryui_version');
1271
1272
	// Show the jquery custom level box only if the option has been selected
1273
	// yes the dt dd stuff makes it this ugly
1274
	if (jqBase === false)
1275
	{
1276
		// dd and the dt
1277
		jqBase_val.parent().slideUp();
1278
		jqBase_val.parent().prev().slideUp();
1279
	}
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1280
	else
1281
	{
1282
		jqBase_val.parent().slideDown();
1283
		jqBase_val.parent().prev().slideDown();
1284
	}
1285
1286
	// And the same for the UI areas as well
1287
	if (jqUi === false)
1288
	{
1289
		// The parent is the dd and the sibling is its dt
1290
		jqUi_val.parent().slideUp();
1291
		jqUi_val.parent().prev().slideUp();
1292
	}
1293
	else
1294
	{
1295
		jqUi_val.parent().slideDown();
1296
		jqUi_val.parent().prev().slideDown();
1297
	}
1298
}
1299
1300
/**
1301
 * Used in manageMembergroups to enable disable form elements based on allowable choices
1302
 * If post based group is selected, it will disable moderation selection, visibility, group description
1303
 * and enable post count input box
1304
 *
1305
 * @param {boolean} isChecked
1306
 */
1307
function swapPostGroup(isChecked)
1308
{
1309
	var min_posts_text = document.getElementById('min_posts_text'),
1310
		group_desc_text = document.getElementById('group_desc_text'),
1311
		group_hidden_text = document.getElementById('group_hidden_text'),
1312
		group_moderators_text = document.getElementById('group_moderators_text');
1313
1314
	document.forms.groupForm.min_posts.disabled = !isChecked;
1315
	min_posts_text.style.color = isChecked ? "" : "#888";
1316
1317
	document.forms.groupForm.group_desc_input.disabled = isChecked;
1318
	group_desc_text.style.color = !isChecked ? "" : "#888";
1319
1320
	document.forms.groupForm.group_hidden_input.disabled = isChecked;
1321
	group_hidden_text.style.color = !isChecked ? "" : "#888";
1322
1323
	document.forms.groupForm.group_moderators.disabled = isChecked;
1324
	group_moderators_text.style.color = !isChecked ? "" : "#888";
1325
1326
	// Disable the moderator autosuggest box as well
1327
	if (typeof(oModeratorSuggest) !== 'undefined')
1328
		oModeratorSuggest.oTextHandle.disabled = !!isChecked;
1329
}
1330
1331
/**
1332
 * Handles the AJAX preview of the warning templates
1333
 */
1334
function ajax_getTemplatePreview()
1335
{
1336
	$.ajax({
1337
		type: "POST",
1338
		url: elk_scripturl + '?action=xmlpreview;xml',
1339
		data: {
1340
			item: "warning_preview",
1341
			title: $("#template_title").val(),
1342
			body: $("#template_body").val(),
1343
			user: $('input[name="u"]').attr("value")
1344
		},
1345
		context: document.body
1346
	})
1347
	.done(function(request) {
1348
		$("#box_preview").css({display:"block"});
1349
		$("#template_preview").html($(request).find('body').text());
1350
1351
		var $_errors = $("#errors");
1352
		if ($(request).find("error").text() !== '')
1353
		{
1354
			$_errors.css({display:"block"});
1355
1356
			var errors_html = '',
1357
			errors = $(request).find('error').each(function() {
0 ignored issues
show
Unused Code introduced by
The variable errors seems to be never used. Consider removing it.
Loading history...
1358
				errors_html += $(this).text() + '<br />';
1359
			});
1360
1361
			$(document).find("#error_list").html(errors_html);
1362
			$('html, body').animate({ scrollTop: $_errors.offset().top }, 'slow');
1363
		}
1364
		else
1365
		{
1366
			$_errors.css({display:"none"});
1367
			$("#error_list").html('');
1368
			$('html, body').animate({ scrollTop: $("#box_preview").offset().top }, 'slow');
1369
		}
1370
1371
		return false;
1372
	});
1373
1374
	return false;
1375
}
1376
1377
/**
1378
 * Sets up all the js events for edit and save board-specific permission
1379
 * profiles
1380
 */
1381
function initEditProfileBoards()
1382
{
1383
	$('.edit_all_board_profiles').on('click', function(e) {
1384
		e.preventDefault();
1385
1386
		$('.edit_board').off('click.elkarte');
1387
	});
1388
1389
	$('.edit_board').show().on('click.elkarte', function(e) {
1390
		var $icon = $(this),
1391
			board_id = $icon.data('boardid'),
1392
			board_profile = $icon.data('boardprofile'),
1393
			$target = $('#edit_board_' + board_id),
1394
			$select = $('<select />')
1395
				.attr('name', 'boardprofile[' + board_id + ']')
1396
				.change(function() {
1397
					$(this).find('option:selected').each(function() {
1398
						if ($(this).attr('value') == board_profile)
1399
							$icon.addClass('nochanges').removeClass('changed');
1400
						else
1401
							$icon.addClass('changed').removeClass('nochanges');
1402
					});
1403
				});
1404
1405
		e.preventDefault();
1406
		$(permission_profiles).each(function(key, value) {
1407
			var $opt = $('<option />').attr('value', value.id).text(value.name);
1408
1409
			if (value.id == board_profile)
1410
				$opt.attr('selected', 'selected');
1411
1412
			$select.append($opt);
1413
		});
1414
1415
		$target.replaceWith($select);
1416
		$select.change();
1417
1418
		$('.edit_all_board_profiles').replaceWith($('<input type="submit" class="right_submit" />')
1419
			.attr('name', 'save_changes')
1420
			.attr('value', txt_save)
1421
		);
1422
		$icon.off('click.elkarte').on('click', function(e) {
1423
			e.preventDefault();
1424
			if ($(this).hasClass('changed'))
1425
				$('input[name="save_changes"]').off('click');
1426
		});
1427
	});
1428
}
1429
1430
/**
1431
 * Creates the image and attaches the event to convert the name of the permission
1432
 * profile into an input to change its name and back.
1433
 *
1434
 * It also removes the "Rename all" and "Remove Selected" buttons
1435
 * and the "Delete" column for consistency
1436
 */
1437
function initEditPermissionProfiles()
1438
{
1439
	// We need a variable to be sure we are going to create only 1 cancel button
1440
	var run_once = false;
1441
1442
	$('.rename_profile').each(function() {
1443
		var $this_profile = $(this);
1444
1445
		$this_profile.after($('<a class="js-ed edit_board" />').attr('href', '#').on('click', function(ev) {
1446
			ev.preventDefault();
1447
1448
			// If we have already created the cancel let's skip it
1449
			if (!run_once)
1450
			{
1451
				var $cancel;
1452
1453
				run_once = true;
1454
				$cancel = $('<a class="js-ed-rm linkbutton" />').on('click', function(ev) {
1455
					ev.preventDefault();
1456
1457
					// js-ed is hopefully a class introduced by this function only
1458
					// Any element with this class will be restored when cancel is clicked
1459
					$('.js-ed').show();
1460
1461
					// js-ed-rm is again a class introduced by this function
1462
					// Any element with this class will be removed when cancelling
1463
					$('.js-ed-rm').remove();
1464
1465
					// The cancel button is removed as well,
1466
					// so we need to generate it again later (if we need it again)
1467
					run_once = false;
1468
1469
					$('#rename').val(txt_permissions_profile_rename);
1470
				}).text(ajax_notification_cancel_text).attr('href', '#');
1471
			}
1472
1473
			$this_profile.after($('<input type="text" class="js-ed-rm input_text" />')
1474
				.attr('name', 'rename_profile[' + $this_profile.data('pid') + ']')
1475
				.val($this_profile.text()));
1476
1477
			// These will have to pop back hitting cancel, so let's prepare them
1478
			$('#rename').addClass('js-ed').val(txt_permissions_commit).before($cancel);
0 ignored issues
show
Bug introduced by
The variable $cancel seems to be used out of scope.

This error can usually be fixed by declaring the variable in the scope where it is used:

function someFunction() {
    (function() {
        var i = 0;
    })();

    // i is not defined.
    alert(i);
}

// This can be fixed by moving the var statement to the outer scope.

function someFunction() {
    var i;
    (function() {
        i = 1;
    })();

    alert(i);
};
Loading history...
1479
			$this_profile.addClass('js-ed').hide();
1480
			$('#delete').addClass('js-ed').hide();
1481
			$('.perm_profile_delete').addClass('js-ed').hide();
1482
			$(this).hide();
1483
		}));
1484
	});
1485
}
1486
1487
/**
1488
 * Attach the AJAX handling of things to the various themes to remove
1489
 * Used in ManageThemes (template_list_themes)
1490
 */
1491
function initDeleteThemes()
1492
{
1493
	$(".delete_theme").on("click", function (event) {
1494
		event.preventDefault();
1495
		var theme_id = $(this).data("theme_id"),
1496
			base_url = $(this).attr("href"),
1497
			pattern = new RegExp(elk_session_var + "=" + elk_session_id + ";(.*)$"),
1498
			tokens = pattern.exec(base_url)[1].split("="),
1499
			token = tokens[1],
1500
			token_var = tokens[0];
1501
1502
		if (confirm(txt_theme_remove_confirm))
0 ignored issues
show
Debugging Code Best Practice introduced by
The confirm UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1503
		{
1504
			$.ajax({
1505
				type: "GET",
1506
				url: base_url + ";api;xml",
1507
				beforeSend: ajax_indicator(true)
1508
			})
1509
			.done(function(request) {
1510
				if ($(request).find("error").length === 0)
1511
				{
1512
					var new_token = $(request).find("token").text(),
1513
						new_token_var = $(request).find("token_var").text();
1514
1515
					$(".theme_" + theme_id).slideToggle("slow", function () {
1516
						$(this).remove();
1517
					});
1518
1519
					$(".delete_theme").each(function () {
1520
						$(this).attr("href", $(this).attr("href").replace(token_var + "=" + token, new_token_var + "=" + new_token));
1521
					});
1522
				}
1523
				// @todo improve error handling
1524
				else
1525
				{
1526
					alert($(request).find("text").text());
0 ignored issues
show
Debugging Code Best Practice introduced by
The alert UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1527
					// Redirect to the delete theme page, though it will result in a token verification error
1528
					window.location = base_url;
1529
				}
1530
			})
1531
			.fail(function(request) {
0 ignored issues
show
Unused Code introduced by
The parameter request is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1532
				window.location = base_url;
1533
			})
1534
			.always(function() {
1535
				// turn off the indicator
1536
				ajax_indicator(false);
1537
			});
1538
		}
1539
	});
1540
}
1541
1542
/**
1543
 * These two functions (navigatePreview and refreshPreview) are used in ManageThemes
1544
 * (template_edit_style) to create a preview of the site with the changed stylesheets
1545
 *
1546
 * @param {string} url
1547
 */
1548
function navigatePreview(url)
1549
{
1550
	var myDoc = new XMLHttpRequest();
1551
1552
	myDoc.onreadystatechange = function ()
1553
	{
1554
		if (myDoc.readyState !== 4)
1555
			return;
1556
1557
		if (myDoc.responseText !== null && myDoc.status === 200)
1558
		{
1559
			previewData = myDoc.responseText;
1560
			document.getElementById('css_preview_box').style.display = "block";
1561
1562
			// Revert to the theme they actually use ;).
1563
			var tempImage = new Image();
1564
			tempImage.src = elk_prepareScriptUrl(elk_scripturl) + 'action=admin;area=theme;sa=edit;theme=' + theme_id + ';preview;' + (new Date().getTime());
1565
1566
			refreshPreviewCache = null;
1567
			refreshPreview(false);
1568
		}
1569
	};
1570
1571
	var anchor = "";
1572
	if (url.indexOf("#") !== -1)
1573
	{
1574
		anchor = url.substr(url.indexOf("#"));
1575
		url = url.substr(0, url.indexOf("#"));
1576
	}
1577
1578
	myDoc.open("GET", url + (url.indexOf("?") === -1 ? "?" : ";") + 'theme=' + theme_id + anchor, true);
1579
	myDoc.send(null);
1580
}
1581
1582
/**
1583
 * Used when editing a stylesheet.  Allows for the preview to be updated to reflect
1584
 * changes made to the css in the editor.
1585
 *
1586
 * @param {boolean} check
1587
 */
1588
function refreshPreview(check)
1589
{
1590
	var identical = document.forms.stylesheetForm.entire_file.value == refreshPreviewCache;
1591
1592
	// Don't reflow the whole thing if nothing changed!!
1593
	if (check && identical)
1594
		return;
1595
1596
	refreshPreviewCache = document.forms.stylesheetForm.entire_file.value;
1597
1598
	// Replace the paths for images.
1599
	refreshPreviewCache = refreshPreviewCache.replace(/url\(\.\.\/images/gi, "url(" + elk_images_url);
1600
1601
	// Try to do it without a complete reparse.
1602
	if (identical)
1603
	{
1604
		try
1605
		{
1606
			if (is_ie)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable is_ie is declared in the current environment, consider using typeof is_ie === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
1607
			{
1608
				var sheets = frames['css_preview_box'].document.styleSheets;
0 ignored issues
show
Coding Style introduced by
['css_preview_box'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1609
				for (var j = 0; j < sheets.length; j++)
1610
				{
1611
					if (sheets[j].id === 'css_preview_box')
1612
						sheets[j].cssText = document.forms.stylesheetForm.entire_file.value;
1613
				}
1614
			}
1615
			else
1616
			{
1617
				frames['css_preview_box'].document.getElementById("css_preview_sheet").innerHTML = document.forms.stylesheetForm.entire_file.value;
0 ignored issues
show
Coding Style introduced by
['css_preview_box'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1618
			}
1619
		}
1620
		catch (e)
1621
		{
1622
			identical = false;
1623
		}
1624
	}
1625
1626
	// This will work most of the time... could be done with an after-apply, maybe.
1627
	if (!identical)
1628
	{
1629
		var data = previewData,
1630
			preview_sheet = document.forms.stylesheetForm.entire_file.value,
1631
			stylesheetMatch = new RegExp('<link rel="stylesheet"[^>]+href="[^"]+' + editFilename + '[^>]*>'),
1632
			iframe;
1633
1634
		// Replace the paths for images.
1635
		preview_sheet = preview_sheet.replace(/url\(\.\.\/images/gi, "url(" + elk_images_url);
1636
		data = data.replace(stylesheetMatch, '<style type="text/css" id="css_preview_sheet">' + preview_sheet + "<" + "/style>");
1637
1638
		iframe = document.getElementById("css_preview_box");
1639
		iframe.contentWindow.document.open();
1640
		iframe.contentWindow.document.write(data);
1641
		iframe.contentWindow.document.close();
1642
1643
		// Next, fix all its links so we can handle them and reapply the new css!
1644
		iframe.onload = function ()
1645
		{
1646
			var fixLinks = frames["css_preview_box"].document.getElementsByTagName("a");
0 ignored issues
show
Coding Style introduced by
['css_preview_box'] could be written in dot notation.

You can rewrite this statement in dot notation:

var obj = { };
obj['foo'] = 'bar'; // Bad
obj.foo = 'bar'; // Good
Loading history...
1647
			for (var i = 0; i < fixLinks.length; i++)
1648
			{
1649
				if (fixLinks[i].onclick)
1650
					continue;
1651
1652
				fixLinks[i].onclick = function ()
0 ignored issues
show
Bug introduced by
It is generally not recommended to make functions within a loop.

While making functions in a loop will not lead to any runtime error, the code might not behave as you expect as the variables in the scope are not imported by value, but by reference. Let’s take a look at an example:

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(function() {
        alert(i);
    });
}

funcs[0](); // alert(10);
funcs[1](); // alert(10);
/// ...
funcs[9](); // alert(10);

If you would instead like to bind the function inside the loop to the value of the variable during that specific iteration, you can create the function from another function:

var createFunc = function(i) {
    return function() {
        alert(i);
    };
};

var funcs = [];
for (var i=0; i<10; i++) {
    funcs.push(createFunc(i));
}

funcs[0](); // alert(0)
funcs[1](); // alert(1)
// ...
funcs[9](); // alert(9)
Loading history...
1653
				{
1654
					window.parent.navigatePreview(this.href);
1655
					return false;
1656
				};
1657
			}
1658
		};
1659
	}
1660
}
1661
1662
/**
1663
 * Callback (onBeforeUpdate) used by the AutoSuggest, used when adding new bans
1664
 *
1665
 * @param {object} oAutoSuggest
1666
 */
1667
function onUpdateName(oAutoSuggest)
0 ignored issues
show
Unused Code introduced by
The parameter oAutoSuggest is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1668
{
1669
	document.getElementById('user_check').checked = true;
1670
	return true;
1671
}
1672
1673
/**
1674
 * Validates that the ban form is filled out properly before submitting
1675
 * Used when editing bans
1676
 *
1677
 * @param {object} aForm this form object to check
1678
 */
1679
function confirmBan(aForm)
1680
{
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
1681
	if (aForm.ban_name.value === '')
1682
	{
1683
		alert(txt_ban_name_empty);
0 ignored issues
show
Debugging Code Best Practice introduced by
The alert UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1684
		return false;
1685
	}
1686
1687
	if (aForm.partial_ban.checked && !(aForm.cannot_post.checked || aForm.cannot_register.checked || aForm.cannot_login.checked))
1688
	{
1689
		alert(txt_ban_restriction_empty);
1690
		return false;
1691
	}
1692
1693
	return true;
1694
}
1695
1696
// Enable/disable some fields when working with bans.
1697
var fUpdateStatus = function ()
1698
{
1699
	document.getElementById("expire_date").disabled = !document.getElementById("expires_one_day").checked;
1700
	document.getElementById("cannot_post").disabled = document.getElementById("full_ban").checked;
1701
	document.getElementById("cannot_register").disabled = document.getElementById("full_ban").checked;
1702
	document.getElementById("cannot_login").disabled = document.getElementById("full_ban").checked;
1703
};
1704
1705
/**
1706
 * Used when setting up subscriptions, used to toggle the currency code divs
1707
 * based on which currencies are chosen.
1708
 */
1709
function toggleCurrencyOther()
1710
{
1711
	var otherOn = document.getElementById("paid_currency").value === 'other',
1712
		currencydd = document.getElementById("custom_currency_code_div_dd");
1713
1714
	if (otherOn)
1715
	{
1716
		document.getElementById("custom_currency_code_div").style.display = "";
1717
		document.getElementById("custom_currency_symbol_div").style.display = "";
1718
1719
		if (currencydd)
1720
		{
1721
			document.getElementById("custom_currency_code_div_dd").style.display = "";
1722
			document.getElementById("custom_currency_symbol_div_dd").style.display = "";
1723
		}
1724
	}
1725
	else
1726
	{
1727
		document.getElementById("custom_currency_code_div").style.display = "none";
1728
		document.getElementById("custom_currency_symbol_div").style.display = "none";
1729
1730
		if (currencydd)
1731
		{
1732
			document.getElementById("custom_currency_symbol_div_dd").style.display = "none";
1733
			document.getElementById("custom_currency_code_div_dd").style.display = "none";
1734
		}
1735
	}
1736
}
1737
1738
/**
1739
 * Used to ajax-ively preview the templates of bounced emails (template_bounce_template)
1740
 */
1741
function ajax_getEmailTemplatePreview()
1742
{
1743
	$.ajax({
1744
		type: "POST",
1745
		url: elk_scripturl + "?action=xmlpreview;xml",
1746
		data: {
1747
			item: "bounce_preview",
1748
			title: $("#template_title").val(),
1749
			body: $("#template_body").val()
1750
		},
1751
		context: document.body
1752
	})
1753
	.done(function(request) {
1754
		// Show the preview section, populated with the response
1755
		$("#preview_section").css({display: "block"});
1756
		$("#preview_body").html($(request).find('body').text());
1757
		$("#preview_subject").html($(request).find('subject').text());
1758
1759
		// Any error we need to let them know about?
1760
		if ($(request).find("error").text() !== '')
1761
		{
1762
			var errors_html = '',
1763
				$_errors = $("#errors"),
1764
				errors;
1765
1766
			// Build the error string
1767
			errors = $(request).find('error').each(function() {
0 ignored issues
show
Unused Code introduced by
The variable errors seems to be never used. Consider removing it.
Loading history...
1768
				errors_html += $(this).text() + '<br />';
1769
			});
1770
1771
			// Add it to the error div, set the class level, and show it
1772
			$(document).find("#error_list").html(errors_html);
1773
			$_errors.css({display: ""});
1774
			$_errors.attr('class', parseInt($(request).find('errors').attr('serious')) === 0 ? 'warningbox' : 'errorbox');
1775
		}
1776
		else
1777
		{
1778
			$("#errors").css({display: "none"});
1779
			$("#error_list").html('');
1780
		}
1781
1782
		// Navigate to the preview
1783
		$('html, body').animate({ scrollTop: $('#preview_section').offset().top }, 'slow');
1784
1785
		return false;
1786
	});
1787
1788
	return false;
1789
}
1790
1791
/**
1792
 * Used to ajax-ively preview a word censor
1793
 * Does no checking, it either gets a result or does nothing
1794
 */
1795
function ajax_getCensorPreview()
1796
{
1797
	$.ajax({
1798
		type: 'POST',
1799
		dataType: 'json',
1800
		url: elk_scripturl + "?action=admin;area=postsettings;sa=censor;xml",
1801
		data: {
1802
			censortest: $("#censortest").val()
1803
		}
1804
	})
1805
	.done(function(request) {
1806
		if (request.result === true) {
1807
			// Show the censored text section, populated with the response
1808
			$("#censor_result").css({display: "block"}).html(request.censor);
1809
1810
			// Update the token
1811
			$("#token").attr({name:request.token_val, value:request.token});
1812
1813
			// Clear the box
1814
			$('#censortest').attr({value:''}).val('');
1815
		}
1816
	});
1817
1818
	return false;
1819
}
1820
1821
/**
1822
 * Used to show/hide sub options for the various notifications
1823
 * action=admin;area=featuresettings;sa=mention
1824
 */
1825
$(function() {
1826
	var $headers = $("#mention").find("input[id^='notifications'][id$='[notification]']");
1827
1828
	$headers.change(function() {
1829
		var $top = $(this).closest('dl'),
1830
			$hparent = $(this).parent();
1831
1832
		if (this.checked)
1833
		{
1834
			$top.find('dt:not(:first-child)').fadeIn();
1835
			$top.find('dd:not(:nth-child(2))').each(function() {
1836
				$(this).fadeIn();
1837
				$(this).find('input').prop('disabled', false);
1838
			});
1839
		}
1840
		else
1841
		{
1842
			$top.find('dt:not(:first-child)').hide();
1843
			$top.find('dd:not(:nth-child(2))').each(function() {
1844
				$(this).hide();
1845
				$(this).find('input').prop('disabled', true);
1846
			});
1847
		}
1848
1849
		$hparent.show();
1850
		$hparent.prev().show();
1851
	});
1852
1853
	$headers.change();
1854
});
1855
1856
/**
1857
 * Ajax function to clear CSS and JS hives.  Called from action=admin;area=featuresettings;sa=basic
1858
 * Remove Hives button.
1859
 */
1860
$(function() {
1861
	$('#clean_hives').on('click', function () {
1862
		var infoBar = new ElkInfoBar('bar_clean_hives');
1863
1864
		$.ajax({
1865
			type: 'POST',
1866
			dataType: 'json',
1867
			url: elk_scripturl + "?action=admin;area=featuresettings;sa=basic;xml;api=json",
1868
			data: {
1869
				cleanhives: true
1870
			}
1871
		})
1872
		.done(function(request) {
1873
			infoBar.changeText(request.response);
1874
1875
			if (request.success === true) {
1876
				infoBar.isSuccess();
1877
			}
1878
			else {
1879
				infoBar.isError();
1880
			}
1881
		})
1882
		.fail(function(request) {
0 ignored issues
show
Unused Code introduced by
The parameter request is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1883
			infoBar.isError();
1884
			infoBar.changeText(txt_invalid_response);
1885
		})
1886
		.always(function(request) {
0 ignored issues
show
Unused Code introduced by
The parameter request is not used and could be removed.

This check looks for parameters in functions that are not used in the function body and are not followed by other parameters which are used inside the function.

Loading history...
1887
			infoBar.showBar();
1888
		});
1889
1890
		return false;
1891
	});
1892
});
1893
1894
/**
1895
 * Enable / disable "core" features of the software. Called from action=admin;area=corefeatures
1896
 */
1897
$(function() {
1898
	if ($('#core_features').length === 0)
1899
	{
1900
		return;
1901
	}
1902
1903
	$(".core_features_hide").css('display', 'none');
1904
	$(".core_features_img").show().css({'cursor': 'pointer'}).each(function() {
1905
		var sImageText = $(this).hasClass('on') ? feature_on_text : feature_off_text;
1906
		$(this).attr({ title: sImageText, alt: sImageText });
1907
	});
1908
	$("#core_features_submit").css('display', 'none');
1909
1910
	if (!token_name)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable token_name is declared in the current environment, consider using typeof token_name === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
1911
		token_name = $("#core_features_token").attr("name");
0 ignored issues
show
Bug introduced by
The variable token_name seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_name.
Loading history...
1912
1913
	if (!token_value)
0 ignored issues
show
Best Practice introduced by
If you intend to check if the variable token_value is declared in the current environment, consider using typeof token_value === "undefined" instead. This is safe if the variable is not actually declared.
Loading history...
1914
		token_value = $("#core_features_token").attr("value");
0 ignored issues
show
Bug introduced by
The variable token_value seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_value.
Loading history...
1915
1916
	// Attach our action to the core features power button
1917
	$(".core_features_img").click(function() {
1918
		var cc = $(this),
1919
			cf = $(this).attr("id").substring(7),
1920
			imgs = new Array(elk_images_url + "/admin/switch_off.png", elk_images_url + "/admin/switch_on.png"),
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
1921
			new_state = !$("#feature_" + cf).attr("checked"),
1922
			ajax_infobar = new ElkInfoBar('core_features_bar', {error_class: 'errorbox', success_class: 'successbox'}),
1923
			data;
1924
1925
		$("#feature_" + cf).attr("checked", new_state);
1926
1927
		data = {save: "save", feature_id: cf};
1928
		data[$("#core_features_session").attr("name")] = $("#core_features_session").val();
1929
		data[token_name] = token_value;
1930
1931
		$(".core_features_status_box").each(function(){
1932
			data[$(this).attr("name")] = !$(this).attr("checked") ? 0 : 1;
1933
		});
1934
1935
		// Launch AJAX request.
1936
		$.ajax({
1937
			// The link we are accessing.
1938
			url: elk_scripturl + "?action=xmlhttp;sa=corefeatures;xml",
1939
1940
			// The type of request.
1941
			type: "post",
1942
1943
			// The type of data that is getting returned.
1944
			data: data
1945
		})
1946
		.done(function(request) {
1947
			if ($(request).find("errors").find("error").length !== 0)
1948
			{
1949
				ajax_infobar.isError();
1950
				ajax_infobar.changeText($(request).find("errors").find("error").text()).showBar();
1951
			}
1952
			else if ($(request).find("elk").length !== 0)
1953
			{
1954
				$("#feature_link_" + cf).html($(request).find("corefeatures").find("corefeature").text());
1955
				cc.attr({
1956
					"src": imgs[new_state ? 1 : 0],
1957
					"title": new_state ? feature_on_text : feature_off_text,
1958
					"alt": new_state ? feature_on_text : feature_off_text
1959
				});
1960
				$("#feature_link_" + cf).fadeOut().fadeIn();
1961
				ajax_infobar.isSuccess();
1962
				var message = $(request).find("messages").find("message").text();
1963
				ajax_infobar.changeText(message).showBar();
1964
1965
				token_name = $(request).find("tokens").find('[type="token"]').text();
0 ignored issues
show
Bug introduced by
The variable token_name seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_name.
Loading history...
1966
				token_value = $(request).find("tokens").find('[type="token_var"]').text();
0 ignored issues
show
Bug introduced by
The variable token_value seems to be never declared. Assigning variables without defining them first makes them global. If this was intended, consider making it explicit like using window.token_value.
Loading history...
1967
			}
1968
			else
1969
			{
1970
				ajax_infobar.isError();
1971
				ajax_infobar.changeText(core_settings_generic_error).showBar();
1972
			}
1973
		})
1974
		.fail(function(error) {
1975
			ajax_infobar.changeText(error).showBar();
1976
		});
1977
	});
1978
});
1979